home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 1 / The Arsenal Files (Arsenal Computer).ISO / archive / unixarc.pt4 < prev    next >
Internet Message Format  |  1994-01-23  |  70KB

  1. From pacbell!ames!mailrus!cornell!rochester!bbn!bbn.com!rsalz Fri Jul  1 13:12:42 1988
  2. From: rsalz@uunet.uu.net (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v15i080:  ARC (PC compression program), v5.21, Part04/05
  5. Message-ID: <968@fig.bbn.com>
  6. Date: 1 Jul 88 20:12:42 GMT
  7.  
  8. Submitted-by: hyc@math.lsa.umich.edu
  9. Posting-number: Volume 15, Issue 80
  10. Archive-name: arc5.21/part04
  11.  
  12. #--------------------------------CUT HERE-------------------------------------
  13. #! /bin/sh
  14. #
  15. # This is a shell archive.  Save this into a file, edit it
  16. # and delete all lines above this comment.  Then give this
  17. # file to sh by executing the command "sh file".  The files
  18. # will be extracted into the current directory owned by
  19. # you with default permissions.
  20. #
  21. # The files contained herein are:
  22. #
  23. # -rw-r--r--  1 hyc         22109 Jun  1 20:01 arclzw.c
  24. # -rw-r--r--  1 hyc          3026 Jun  1 19:41 arcmatch.c
  25. # -rw-r--r--  1 hyc          8418 Jun 13 14:17 arcmisc.c
  26. # -rw-r--r--  1 hyc          7376 Jun  2 16:27 arcpack.c
  27. # -rw-r--r--  1 hyc          3838 Jun  1 19:57 arcrun.c
  28. # -rw-r--r--  1 hyc          1645 Apr 17 18:53 arcs.h
  29. # -rw-------  1 hyc         14613 Jun  2 16:27 arcsq.c
  30. #
  31. echo 'x - arclzw.c'
  32. if test -f arclzw.c; then echo 'shar: not overwriting arclzw.c'; else
  33. sed 's/^X//' << '________This_Is_The_END________' > arclzw.c
  34. X/*
  35. X * $Header: arclzw.c,v 1.4 88/06/01 16:27:59 hyc Locked $
  36. X */
  37. X
  38. X/*
  39. X * ARC - Archive utility - ARCLZW
  40. X * 
  41. X * Version 2.03, created on 10/24/86 at 11:46:22
  42. X * 
  43. X * (C) COPYRIGHT 1985,86 by System Enhancement Associates; ALL RIGHTS RESERVED
  44. X * 
  45. X * By:  Thom Henderson
  46. X * 
  47. X * Description: This file contains the routines used to implement Lempel-Zev
  48. X * data compression, which calls for building a coding table on the fly.
  49. X * This form of compression is especially good for encoding files which
  50. X * contain repeated strings, and can often give dramatic improvements over
  51. X * traditional Huffman SQueezing.
  52. X * 
  53. X * Language: Computer Innovations Optimizing C86
  54. X * 
  55. X * Programming notes: In this section I am drawing heavily on the COMPRESS
  56. X * program from UNIX.  The basic method is taken from "A Technique for High
  57. X * Performance Data Compression", Terry A. Welch, IEEE Computer Vol 17, No 6
  58. X * (June 1984), pp 8-19.  Also see "Knuth's Fundamental Algorithms", Donald
  59. X * Knuth, Vol 3, Section 6.4.
  60. X * 
  61. X * As best as I can tell, this method works by tracing down a hash table of code
  62. X * strings where each entry has the property:
  63. X * 
  64. X * if <string> <char> is in the table then <string> is in the table.
  65. X */
  66. X#include <stdio.h>
  67. X#include "arc.h"
  68. X
  69. Xvoid    putc_pak(), abort(), putc_ncr();
  70. Xint    getc_unp();
  71. X#if    MSDOS
  72. Xchar    *setmem();
  73. X#else
  74. Xchar    *memset();
  75. X#endif
  76. X
  77. Xstatic void    putcode();
  78. X/* definitions for older style crunching */
  79. X
  80. X#define FALSE    0
  81. X#define TRUE     !FALSE
  82. X#define TABSIZE  4096
  83. X#define NO_PRED  0xFFFF
  84. X#define EMPTY    0xFFFF
  85. X#define NOT_FND  0xFFFF
  86. X
  87. Xstatic unsigned short inbuf;    /* partial input code storage */
  88. Xstatic int      sp;        /* current stack pointer */
  89. X
  90. Xstruct entry {        /* string table entry format */
  91. X    char            used;    /* true when this entry is in use */
  92. X    unsigned char   follower;    /* char following string */
  93. X    unsigned short  next;    /* ptr to next in collision list */
  94. X    unsigned short  predecessor;    /* code for preceeding string */
  95. X};            /* string_tab[TABSIZE];    /* the code string table */
  96. X
  97. X
  98. X/* definitions for the new dynamic Lempel-Zev crunching */
  99. X
  100. X#define BITS   12        /* maximum bits per code */
  101. X#define HSIZE  5003        /* 80% occupancy */
  102. X#define INIT_BITS 9        /* initial number of bits/code */
  103. X
  104. Xstatic int      n_bits;        /* number of bits/code */
  105. Xstatic int      maxcode;    /* maximum code, given n_bits */
  106. X#define MAXCODE(n)      ((1<<(n)) - 1)    /* maximum code calculation */
  107. Xstatic int      maxcodemax = 1 << BITS;    /* largest possible code (+1) */
  108. X
  109. Xstatic char     buf[BITS];    /* input/output buffer */
  110. X
  111. Xstatic unsigned char lmask[9] =    /* left side masks */
  112. X{
  113. X 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00
  114. X};
  115. Xstatic unsigned char rmask[9] =    /* right side masks */
  116. X{
  117. X 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
  118. X};
  119. X
  120. Xstatic int      offset;        /* byte offset for code output */
  121. Xstatic long     in_count;    /* length of input */
  122. Xstatic long     bytes_out;    /* length of compressed output */
  123. Xstatic long     bytes_ref;    /* output quality reference */
  124. Xstatic long     bytes_last;    /* output size at last checkpoint */
  125. Xstatic unsigned short ent;
  126. X
  127. X/*
  128. X * To save much memory (which we badly need at this point), we overlay the
  129. X * table used by the previous version of Lempel-Zev with those used by the
  130. X * new version.  Since no two of these routines will be used together, we can
  131. X * safely do this.
  132. X */
  133. X
  134. Xextern long     htab[HSIZE];        /* hash code table   (crunch) */
  135. Xextern unsigned short codetab[HSIZE];    /* string code table (crunch) */
  136. Xstatic struct    entry *string_tab=(struct entry *)htab;    /* old crunch string table */
  137. X
  138. Xstatic unsigned short *prefix=codetab;    /* prefix code table (uncrunch) */
  139. Xstatic unsigned char *suffix=(unsigned char *)htab;    /* suffix table (uncrunch) */
  140. X
  141. Xstatic int      free_ent;    /* first unused entry */
  142. Xstatic int      firstcmp;    /* true at start of compression */
  143. Xextern unsigned char stack[HSIZE];    /* local push/pop stack */
  144. X
  145. X/*
  146. X * block compression parameters -- after all codes are used up, and
  147. X * compression rate changes, start over.
  148. X */
  149. X
  150. Xstatic int      clear_flg;
  151. X#define CHECK_GAP 2048        /* ratio check interval */
  152. Xstatic long     checkpoint;
  153. Xvoid            upd_tab();
  154. X
  155. X/*
  156. X * the next two codes should not be changed lightly, as they must not lie
  157. X * within the contiguous general code space.
  158. X */
  159. X#define FIRST   257        /* first free entry */
  160. X#define CLEAR   256        /* table clear output code */
  161. X
  162. X/*
  163. X * The cl_block() routine is called at each checkpoint to determine if
  164. X * compression would likely improve by resetting the code table.  The method
  165. X * chosen to determine this is based on empirical observation that, in
  166. X * general, every 2k of input data should compress at least as well as the
  167. X * first 2k of input.
  168. X */
  169. X
  170. Xstatic          void
  171. Xcl_block(t)            /* table clear for block compress */
  172. X    FILE           *t;    /* our output file */
  173. X{
  174. X    checkpoint = in_count + CHECK_GAP;
  175. X
  176. X    if (bytes_ref) {
  177. X        if (bytes_out - bytes_last > bytes_ref) {
  178. X            setmem(htab, HSIZE * sizeof(long), 0xff);
  179. X            free_ent = FIRST;
  180. X            clear_flg = 1;
  181. X            putcode(CLEAR, t);
  182. X            bytes_ref = 0;
  183. X        }
  184. X    } else
  185. X        bytes_ref = bytes_out - bytes_last;
  186. X
  187. X    bytes_last = bytes_out;    /* remember where we were */
  188. X}
  189. X
  190. X/*****************************************************************
  191. X *
  192. X * Output a given code.
  193. X * Inputs:
  194. X *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
  195. X *              that n_bits =< (LONG)wordsize - 1.
  196. X * Outputs:
  197. X *      Outputs code to the file.
  198. X * Assumptions:
  199. X *      Chars are 8 bits long.
  200. X * Algorithm:
  201. X *      Maintain a BITS character long buffer (so that 8 codes will
  202. X * fit in it exactly).  When the buffer fills up empty it and start over.
  203. X */
  204. X
  205. Xstatic          void
  206. Xputcode(code, t)        /* output a code */
  207. X    int             code;    /* code to output */
  208. X    FILE           *t;    /* where to put it */
  209. X{
  210. X    int             r_off = offset;    /* right offset */
  211. X    int             bits = n_bits;    /* bits to go */
  212. X    char           *bp = buf;    /* buffer pointer */
  213. X    int             n;    /* index */
  214. X
  215. X    register int    ztmp;
  216. X
  217. X    if (code >= 0) {    /* if a real code *//* Get to the first byte. */
  218. X        bp += (r_off >> 3);
  219. X        r_off &= 7;
  220. X
  221. X        /*
  222. X         * Since code is always >= 8 bits, only need to mask the
  223. X         * first hunk on the left. 
  224. X         */
  225. X        ztmp = (code << r_off) & lmask[r_off];
  226. X        *bp = (*bp & rmask[r_off]) | ztmp;
  227. X        bp++;
  228. X        bits -= (8 - r_off);
  229. X        code >>= (8 - r_off);
  230. X
  231. X        /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  232. X        if (bits >= 8) {
  233. X            *bp++ = code;
  234. X            code >>= 8;
  235. X            bits -= 8;
  236. X        }
  237. X        /* Last bits. */
  238. X        if (bits)
  239. X            *bp = code;
  240. X        offset += n_bits;
  241. X
  242. X        if (offset == (n_bits << 3)) {
  243. X            bp = buf;
  244. X            bits = n_bits;
  245. X            bytes_out += bits;
  246. X            do
  247. X                putc_pak(*bp++, t);
  248. X            while (--bits);
  249. X            offset = 0;
  250. X        }
  251. X        /*
  252. X         * If the next entry is going to be too big for the code
  253. X         * size, then increase it, if possible. 
  254. X         */
  255. X        if (free_ent > maxcode || clear_flg > 0) {
  256. X            /*
  257. X             * Write the whole buffer, because the input side
  258. X             * won't discover the size increase until after
  259. X             * it has read it. 
  260. X             */
  261. X            if (offset > 0) {
  262. X                bp = buf;    /* reset pointer for writing */
  263. X                bytes_out += n = n_bits;
  264. X                while (n--)
  265. X                    putc_pak(*bp++, t);
  266. X            }
  267. X            offset = 0;
  268. X
  269. X            if (clear_flg) {    /* reset if clearing */
  270. X                maxcode = MAXCODE(n_bits = INIT_BITS);
  271. X                clear_flg = 0;
  272. X            } else {/* else use more bits */
  273. X                n_bits++;
  274. X                if (n_bits == BITS)
  275. X                    maxcode = maxcodemax;
  276. X                else
  277. X                    maxcode = MAXCODE(n_bits);
  278. X            }
  279. X        }
  280. X    } else {        /* dump the buffer on EOF */
  281. X        bytes_out += n = (offset + 7) / 8;
  282. X
  283. X        if (offset > 0)
  284. X            while (n--)
  285. X                putc_pak(*bp++, t);
  286. X        offset = 0;
  287. X    }
  288. X}
  289. X
  290. X/*****************************************************************
  291. X *
  292. X * Read one code from the standard input.  If EOF, return -1.
  293. X * Inputs:
  294. X *      cmpin
  295. X * Outputs:
  296. X *      code or -1 is returned.
  297. X */
  298. X
  299. Xstatic          int
  300. Xgetcode(f)            /* get a code */
  301. X    FILE           *f;    /* file to get from */
  302. X{
  303. X    int             code;
  304. X    static int      offset = 0, size = 0;
  305. X    int             r_off, bits;
  306. X    unsigned char  *bp = (unsigned char *) buf;
  307. X
  308. X    if (clear_flg > 0 || offset >= size || free_ent > maxcode) {
  309. X        /*
  310. X         * If the next entry will be too big for the current code
  311. X         * size, then we must increase the size. This implies
  312. X         * reading a new buffer full, too. 
  313. X         */
  314. X        if (free_ent > maxcode) {
  315. X            n_bits++;
  316. X            if (n_bits == BITS)
  317. X                maxcode = maxcodemax;    /* won't get any bigger
  318. X                             * now */
  319. X            else
  320. X                maxcode = MAXCODE(n_bits);
  321. X        }
  322. X        if (clear_flg > 0) {
  323. X            maxcode = MAXCODE(n_bits = INIT_BITS);
  324. X            clear_flg = 0;
  325. X        }
  326. X        for (size = 0; size < n_bits; size++) {
  327. X            if ((code = getc_unp(f)) == EOF)
  328. X                break;
  329. X            else
  330. X                buf[size] = (char) code;
  331. X        }
  332. X        if (size <= 0)
  333. X            return -1;    /* end of file */
  334. X
  335. X        offset = 0;
  336. X        /* Round size down to integral number of codes */
  337. X        size = (size << 3) - (n_bits - 1);
  338. X    }
  339. X    r_off = offset;
  340. X    bits = n_bits;
  341. X
  342. X    /*
  343. X     * Get to the first byte. 
  344. X     */
  345. X    bp += (r_off >> 3);
  346. X    r_off &= 7;
  347. X
  348. X    /* Get first part (low order bits) */
  349. X    code = (*bp++ >> r_off);
  350. X    bits -= 8 - r_off;
  351. X    r_off = 8 - r_off;    /* now, offset into code word */
  352. X
  353. X    /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  354. X    if (bits >= 8) {
  355. X        code |= *bp++ << r_off;
  356. X        r_off += 8;
  357. X        bits -= 8;
  358. X    }
  359. X    /* high order bits. */
  360. X    code |= (*bp & rmask[bits]) << r_off;
  361. X    offset += n_bits;
  362. X
  363. X    return code & MAXCODE(BITS);
  364. X}
  365. X
  366. X/*
  367. X * compress a file
  368. X * 
  369. X * Algorithm:  use open addressing double hashing (no chaining) on the prefix
  370. X * code / next character combination.  We do a variant of Knuth's algorithm D
  371. X * (vol. 3, sec. 6.4) along with G. Knott's relatively-prime secondary probe.
  372. X * Here, the modular division first probe is gives way to a faster
  373. X * exclusive-or manipulation.  Also do block compression with an adaptive
  374. X * reset, where the code table is cleared when the compression ratio
  375. X * decreases, but after the table fills.  The variable-length output codes
  376. X * are re-sized at this point, and a special CLEAR code is generated for the
  377. X * decompressor.
  378. X */
  379. X
  380. Xvoid
  381. Xinit_cm(t)            /* initialize for compression */
  382. X    FILE           *t;    /* where compressed file goes */
  383. X{
  384. X    offset = 0;
  385. X    bytes_out = bytes_last = 1;
  386. X    bytes_ref = 0;
  387. X    clear_flg = 0;
  388. X    in_count = 1;
  389. X    checkpoint = CHECK_GAP;
  390. X    maxcode = MAXCODE(n_bits = INIT_BITS);
  391. X    free_ent = FIRST;
  392. X    setmem(htab, HSIZE * sizeof(long), 0xff);
  393. X    n_bits = INIT_BITS;    /* set starting code size */
  394. X
  395. X    putc_pak(BITS, t);    /* note our max code length */
  396. X
  397. X    firstcmp = 1;        /* next byte will be first */
  398. X}
  399. X
  400. Xvoid
  401. Xputc_cm(c, t)            /* compress a character */
  402. X    unsigned char   c;    /* character to compress */
  403. X    FILE           *t;    /* where to put it */
  404. X{
  405. X    static long     fcode;
  406. X    static int      hshift;
  407. X    int             i;
  408. X    int             disp;
  409. X
  410. X    if (firstcmp) {        /* special case for first byte */
  411. X        ent = c;    /* remember first byte */
  412. X
  413. X        hshift = 0;
  414. X        for (fcode = (long) HSIZE; fcode < 65536L; fcode *= 2L)
  415. X            hshift++;
  416. X        hshift = 8 - hshift;    /* set hash code range bound */
  417. X
  418. X        firstcmp = 0;    /* no longer first */
  419. X        return;
  420. X    }
  421. X    in_count++;
  422. X
  423. X    fcode = (long) (((long) c << BITS) + ent);
  424. X    i = (c << hshift) ^ ent;/* xor hashing */
  425. X
  426. X    if (htab[i] == fcode) {
  427. X        ent = codetab[i];
  428. X        return;
  429. X    } else if (htab[i] < 0)    /* empty slot */
  430. X        goto nomatch;
  431. X    disp = HSIZE - i;    /* secondary hash (after G.Knott) */
  432. X    if (i == 0)
  433. X        disp = 1;
  434. X
  435. Xprobe:
  436. X    if ((i -= disp) < 0)
  437. X        i += HSIZE;
  438. X
  439. X    if (htab[i] == fcode) {
  440. X        ent = codetab[i];
  441. X        return;
  442. X    }
  443. X    if (htab[i] > 0)
  444. X        goto probe;
  445. X
  446. Xnomatch:
  447. X    putcode(ent, t);
  448. X    ent = c;
  449. X    if (free_ent < maxcodemax) {
  450. X        codetab[i] = free_ent++;    /* code -> hashtable */
  451. X        htab[i] = fcode;
  452. X    }
  453. X    if (in_count >= checkpoint)
  454. X        cl_block(t);    /* check for adaptive reset */
  455. X}
  456. X
  457. Xlong
  458. Xpred_cm(t)            /* finish compressing a file */
  459. X    FILE           *t;    /* where to put it */
  460. X{
  461. X    putcode(ent, t);    /* put out the final code */
  462. X    putcode(-1, t);        /* tell output we are done */
  463. X
  464. X    return bytes_out;    /* say how big it got */
  465. X}
  466. X
  467. X/*
  468. X * Decompress a file.  This routine adapts to the codes in the file building
  469. X * the string table on-the-fly; requiring no table to be stored in the
  470. X * compressed file.  The tables used herein are shared with those of the
  471. X * compress() routine.  See the definitions above.
  472. X */
  473. X
  474. Xvoid
  475. Xdecomp(f, t)            /* decompress a file */
  476. X    FILE           *f;    /* file to read codes from */
  477. X    FILE           *t;    /* file to write text to */
  478. X{
  479. X    unsigned char  *stackp;
  480. X    int             finchar;
  481. X    int             code, oldcode, incode;
  482. X
  483. X    if ((code = getc_unp(f)) != BITS)
  484. X        abort("File packed with %d bits, I can only handle %d", code, BITS);
  485. X
  486. X    n_bits = INIT_BITS;    /* set starting code size */
  487. X    clear_flg = 0;
  488. X
  489. X    /*
  490. X     * As above, initialize the first 256 entries in the table. 
  491. X     */
  492. X    maxcode = MAXCODE(n_bits = INIT_BITS);
  493. X    setmem(prefix, 256 * sizeof(short), 0);    /* reset decode string table */
  494. X    for (code = 255; code >= 0; code--)
  495. X        suffix[code] = (unsigned char) code;
  496. X
  497. X    free_ent = FIRST;
  498. X
  499. X    finchar = oldcode = getcode(f);
  500. X    if (oldcode == -1)    /* EOF already? */
  501. X        return;        /* Get out of here */
  502. X    putc_ncr((unsigned char) finchar, t);    /* first code must be 8 bits=char */
  503. X    stackp = stack;
  504. X
  505. X    while ((code = getcode(f)) > -1) {
  506. X        if (code == CLEAR) {    /* reset string table */
  507. X            setmem(prefix, 256 * sizeof(short), 0);
  508. X            clear_flg = 1;
  509. X            free_ent = FIRST - 1;
  510. X            if ((code = getcode(f)) == -1)    /* O, untimely death! */
  511. X                break;
  512. X        }
  513. X        incode = code;
  514. X        /*
  515. X         * Special case for KwKwK string. 
  516. X         */
  517. X        if (code >= free_ent) {
  518. X            if (code > free_ent) {
  519. X                if (warn) {
  520. X                    printf("Corrupted compressed file.\n");
  521. X                    printf("Invalid code %d when max is %d.\n",
  522. X                        code, free_ent);
  523. X                }
  524. X                nerrs++;
  525. X                return;
  526. X            }
  527. X            *stackp++ = finchar;
  528. X            code = oldcode;
  529. X        }
  530. X        /*
  531. X         * Generate output characters in reverse order 
  532. X         */
  533. X        while (code >= 256) {
  534. X            *stackp++ = suffix[code];
  535. X            code = prefix[code];
  536. X        }
  537. X        *stackp++ = finchar = suffix[code];
  538. X
  539. X        /*
  540. X         * And put them out in forward order 
  541. X         */
  542. X        do
  543. X            putc_ncr(*--stackp, t);
  544. X        while (stackp > stack);
  545. X
  546. X        /*
  547. X         * Generate the new entry. 
  548. X         */
  549. X        if ((code = free_ent) < maxcodemax) {
  550. X            prefix[code] = (unsigned short) oldcode;
  551. X            suffix[code] = finchar;
  552. X            free_ent = code + 1;
  553. X        }
  554. X        /*
  555. X         * Remember previous code. 
  556. X         */
  557. X        oldcode = incode;
  558. X    }
  559. X}
  560. X
  561. X
  562. X/*************************************************************************
  563. X * Please note how much trouble it can be to maintain upwards            *
  564. X * compatibility.  All that follows is for the sole purpose of unpacking *
  565. X * files which were packed using an older method.                        *
  566. X *************************************************************************/
  567. X
  568. X
  569. X/*
  570. X * The h() pointer points to the routine to use for calculating a hash value.
  571. X * It is set in the init routines to point to either of oldh() or newh().
  572. X * 
  573. X * oldh() calculates a hash value by taking the middle twelve bits of the square
  574. X * of the key.
  575. X * 
  576. X * newh() works somewhat differently, and was tried because it makes ARC about
  577. X * 23% faster.  This approach was abandoned because dynamic Lempel-Zev
  578. X * (above) works as well, and packs smaller also.  However, inadvertent
  579. X * release of a developmental copy forces us to leave this in.
  580. X */
  581. X
  582. Xstatic unsigned short(*h) ();    /* pointer to hash function */
  583. X
  584. Xstatic unsigned short
  585. Xoldh(pred, foll)        /* old hash function */
  586. X    unsigned short  pred;    /* code for preceeding string */
  587. X    unsigned char   foll;    /* value of following char */
  588. X{
  589. X    long            local;    /* local hash value */
  590. X
  591. X    local = ((pred + foll) | 0x0800) & 0xFFFF; /* create the hash key */
  592. X    local *= local;        /* square it */
  593. X    return (local >> 6) & 0x0FFF;    /* return the middle 12 bits */
  594. X}
  595. X
  596. Xstatic unsigned short
  597. Xnewh(pred, foll)        /* new hash function */
  598. X    unsigned short  pred;    /* code for preceeding string */
  599. X    unsigned char   foll;    /* value of following char */
  600. X{
  601. X    return (((pred + foll) & 0xFFFF) * 15073) & 0xFFF; /* faster hash */
  602. X}
  603. X
  604. X/*
  605. X * The eolist() function is used to trace down a list of entries with
  606. X * duplicate keys until the last duplicate is found.
  607. X */
  608. X
  609. Xstatic unsigned short
  610. Xeolist(index)            /* find last duplicate */
  611. X    unsigned short  index;
  612. X{
  613. X    int             temp;
  614. X
  615. X    while (temp = string_tab[index].next)    /* while more duplicates */
  616. X        index = temp;
  617. X
  618. X    return index;
  619. X}
  620. X
  621. X/*
  622. X * The hash() routine is used to find a spot in the hash table for a new
  623. X * entry.  It performs a "hash and linear probe" lookup, using h() to
  624. X * calculate the starting hash value and eolist() to perform the linear
  625. X * probe.  This routine DOES NOT detect a table full condition.  That MUST be
  626. X * checked for elsewhere.
  627. X */
  628. X
  629. Xstatic unsigned short
  630. Xhash(pred, foll)        /* find spot in the string table */
  631. X    unsigned short  pred;    /* code for preceeding string */
  632. X    unsigned char   foll;    /* char following string */
  633. X{
  634. X    unsigned short  local, tempnext;    /* scratch storage */
  635. X    struct entry   *ep;    /* allows faster table handling */
  636. X
  637. X    local = (*h) (pred, foll);    /* get initial hash value */
  638. X
  639. X    if (!string_tab[local].used)    /* if that spot is free */
  640. X        return local;    /* then that's all we need */
  641. X
  642. X    else {            /* else a collision has occured */
  643. X        local = eolist(local);    /* move to last duplicate */
  644. X
  645. X        /*
  646. X         * We must find an empty spot. We start looking 101 places
  647. X         * down the table from the last duplicate. 
  648. X         */
  649. X
  650. X        tempnext = (local + 101) & 0x0FFF;
  651. X        ep = &string_tab[tempnext];    /* initialize pointer */
  652. X
  653. X        while (ep->used) {    /* while empty spot not found */
  654. X            if (++tempnext == TABSIZE) {    /* if we are at the end */
  655. X                tempnext = 0;    /* wrap to beginning of table */
  656. X                ep = string_tab;
  657. X            } else
  658. X                ++ep;    /* point to next element in table */
  659. X        }
  660. X
  661. X        /*
  662. X         * local still has the pointer to the last duplicate, while
  663. X         * tempnext has the pointer to the spot we found.  We use
  664. X         * this to maintain the chain of pointers to duplicates. 
  665. X         */
  666. X
  667. X        string_tab[local].next = tempnext;
  668. X
  669. X        return tempnext;
  670. X    }
  671. X}
  672. X
  673. X/*
  674. X * The init_tab() routine is used to initialize our hash table. You realize,
  675. X * of course, that "initialize" is a complete misnomer.
  676. X */
  677. X
  678. Xstatic          void
  679. Xinit_tab()
  680. X{                /* set ground state in hash table */
  681. X    unsigned int    i;    /* table index */
  682. X
  683. X    setmem((char *) string_tab, sizeof(string_tab), 0);
  684. X
  685. X    for (i = 0; i < 256; i++)    /* list all single byte strings */
  686. X        upd_tab(NO_PRED, i);
  687. X
  688. X    inbuf = EMPTY;        /* nothing is in our buffer */
  689. X}
  690. X
  691. X/*
  692. X * The upd_tab routine is used to add a new entry to the string table. As
  693. X * previously stated, no checks are made to ensure that the table has any
  694. X * room.  This must be done elsewhere.
  695. X */
  696. X
  697. Xvoid
  698. Xupd_tab(pred, foll)        /* add an entry to the table */
  699. X    unsigned short  pred;    /* code for preceeding string */
  700. X    unsigned short  foll;    /* character which follows string */
  701. X{
  702. X    struct entry   *ep;    /* pointer to current entry */
  703. X
  704. X    /* calculate offset just once */
  705. X
  706. X    ep = &string_tab[hash(pred, foll)];
  707. X
  708. X    ep->used = TRUE;    /* this spot is now in use */
  709. X    ep->next = 0;        /* no duplicates after this yet */
  710. X    ep->predecessor = pred;    /* note code of preceeding string */
  711. X    ep->follower = foll;    /* note char after string */
  712. X}
  713. X
  714. X/*
  715. X * This algorithm encoded a file into twelve bit strings (three nybbles). The
  716. X * gocode() routine is used to read these strings a byte (or two) at a time.
  717. X */
  718. X
  719. Xstatic          int
  720. Xgocode(fd)            /* read in a twelve bit code */
  721. X    FILE           *fd;    /* file to get code from */
  722. X{
  723. X    unsigned short  localbuf, returnval;
  724. X    int             temp;
  725. X
  726. X    if (inbuf == EMPTY) {    /* if on a code boundary */
  727. X        if ((temp = getc_unp(fd)) == EOF)    /* get start of next
  728. X                             * code */
  729. X            return EOF;    /* pass back end of file status */
  730. X        localbuf = temp & 0xFF;    /* mask down to true byte value */
  731. X        if ((temp = getc_unp(fd)) == EOF)
  732. X            /* get end of code, * start of next */
  733. X            return EOF;    /* this should never happen */
  734. X        inbuf = temp & 0xFF;    /* mask down to true byte value */
  735. X
  736. X        returnval = ((localbuf << 4) & 0xFF0) + ((inbuf >> 4) & 0x00F);
  737. X        inbuf &= 0x000F;/* leave partial code pending */
  738. X    } else {        /* buffer contains first nybble */
  739. X        if ((temp = getc_unp(fd)) == EOF)
  740. X            return EOF;
  741. X        localbuf = temp & 0xFF;
  742. X
  743. X        returnval = localbuf + ((inbuf << 8) & 0xF00);
  744. X        inbuf = EMPTY;    /* note no hanging nybbles */
  745. X    }
  746. X    return returnval;    /* pass back assembled code */
  747. X}
  748. X
  749. Xstatic          void
  750. Xpush(c)                /* push char onto stack */
  751. X    int             c;    /* character to push */
  752. X{
  753. X    stack[sp] = ((char) c);    /* coerce integer into a char */
  754. X
  755. X    if (++sp >= TABSIZE)
  756. X        abort("Stack overflow\n");
  757. X}
  758. X
  759. Xstatic          int
  760. Xpop()
  761. X{                /* pop character from stack */
  762. X    if (sp > 0)
  763. X        return ((int) stack[--sp]);    /* leave ptr at next empty
  764. X                         * slot */
  765. X
  766. X    else
  767. X        return EMPTY;
  768. X}
  769. X
  770. X/***** LEMPEL-ZEV DECOMPRESSION *****/
  771. X
  772. Xstatic int      code_count;    /* needed to detect table full */
  773. Xstatic int      firstc;        /* true only on first character */
  774. X
  775. Xvoid
  776. Xinit_ucr(new)            /* get set for uncrunching */
  777. X    int             new;    /* true to use new hash function */
  778. X{
  779. X    if (new)        /* set proper hash function */
  780. X        h = newh;
  781. X    else
  782. X        h = oldh;
  783. X
  784. X    sp = 0;            /* clear out the stack */
  785. X    init_tab();        /* set up atomic code definitions */
  786. X    code_count = TABSIZE - 256;    /* note space left in table */
  787. X    firstc = 1;        /* true only on first code */
  788. X}
  789. X
  790. Xint
  791. Xgetc_ucr(f)            /* get next uncrunched byte */
  792. X    FILE           *f;    /* file containing crunched data */
  793. X{
  794. X    int             code, newcode;
  795. X    static int      oldcode, finchar;
  796. X    struct entry   *ep;    /* allows faster table handling */
  797. X
  798. X    if (firstc) {        /* first code is always known */
  799. X        firstc = FALSE;    /* but next will not be first */
  800. X        oldcode = gocode(f);
  801. X        return finchar = string_tab[oldcode].follower;
  802. X    }
  803. X    if (!sp) {        /* if stack is empty */
  804. X        if ((code = newcode = gocode(f)) == EOF)
  805. X            return EOF;
  806. X
  807. X        ep = &string_tab[code];    /* initialize pointer */
  808. X
  809. X        if (!ep->used) {/* if code isn't known */
  810. X            code = oldcode;
  811. X            ep = &string_tab[code];    /* re-initialize pointer */
  812. X            push(finchar);
  813. X        }
  814. X        while (ep->predecessor != NO_PRED) {
  815. X            push(ep->follower);    /* decode string backwards */
  816. X            code = ep->predecessor;
  817. X            ep = &string_tab[code];
  818. X        }
  819. X
  820. X        push(finchar = ep->follower);    /* save first character also */
  821. X
  822. X        /*
  823. X         * The above loop will terminate, one way or another, with
  824. X         * string_tab[code].follower equal to the first character in
  825. X         * the string. 
  826. X         */
  827. X
  828. X        if (code_count) {    /* if room left in string table */
  829. X            upd_tab(oldcode, finchar);
  830. X            --code_count;
  831. X        }
  832. X        oldcode = newcode;
  833. X    }
  834. X    return pop();        /* return saved character */
  835. X}
  836. ________This_Is_The_END________
  837. if test `wc -c < arclzw.c` -ne    22109; then
  838.     echo 'shar: arclzw.c was damaged during transit (should have been    22109 bytes)'
  839. fi
  840. fi        ; : end of overwriting check
  841. echo 'x - arcmatch.c'
  842. if test -f arcmatch.c; then echo 'shar: not overwriting arcmatch.c'; else
  843. sed 's/^X//' << '________This_Is_The_END________' > arcmatch.c
  844. X/*
  845. X * $Header: arcmatch.c,v 1.5 88/06/01 19:41:08 hyc Locked $
  846. X */
  847. X
  848. X/*
  849. X * ARC - Archive utility - ARCMATCH
  850. X * 
  851. X * Version 2.17, created on 12/17/85 at 20:32:18
  852. X * 
  853. X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
  854. X * 
  855. X * By:  Thom Henderson
  856. X * 
  857. X * Description: This file contains service routines needed to maintain an
  858. X * archive.
  859. X * 
  860. X * Language: Computer Innovations Optimizing C86
  861. X */
  862. X#include <stdio.h>
  863. X#include "arc.h"
  864. X
  865. Xint    strcmp(), strlen();
  866. Xvoid    abort();
  867. Xchar    *strcpy();
  868. X
  869. Xint
  870. Xmatch(n, t)            /* test name against template */
  871. X    char           *n;    /* name to test */
  872. X    char           *t;    /* template to test against */
  873. X{
  874. X#if    MTS
  875. X    fortran         patbuild(), patmatch(), patfree();
  876. X    static int      patlen = (-1);
  877. X    static int      patwork = 0;
  878. X    static int      patswch = 0;
  879. X    char            patccid[4];
  880. X    static char     patchar[2] = "?";
  881. X    static char     oldtemp[16] = 0;
  882. X    int             namlen, RETCODE;
  883. X
  884. X    if (strcmp(t, oldtemp)) {
  885. X        if (patwork)
  886. X            patfree(&patwork);
  887. X        strcpy(oldtemp, t);
  888. X        patlen = strlen(oldtemp);
  889. X        patbuild(oldtemp, &patlen, &patwork, &patswch, patccid, patchar, _retcode RETCODE);
  890. X        if (RETCODE > 8) {
  891. X            printf("MTS: patbuild returned %d\n", RETCODE);
  892. X            abort("bad wildcard in filename");
  893. X        }
  894. X    }
  895. X    namlen = strlen(n);
  896. X    patmatch(n, &namlen, &patwork, _retcode RETCODE);
  897. X    switch (RETCODE) {
  898. X    case 0:
  899. X        return (1);
  900. X    case 4:
  901. X        return (0);
  902. X    default:
  903. X        abort("wildcard pattern match failed");
  904. X    }
  905. X}
  906. X
  907. X#else
  908. X#if    !UNIX
  909. X    upper(n);
  910. X    upper(t);        /* avoid case problems */
  911. X#endif    /* UNIX */
  912. X#if    GEMDOS
  913. X    return(pnmatch(n, t, 0));
  914. X#else
  915. X    /* first match name part */
  916. X
  917. X    while ((*n && *n != '.') || (*t && *t != '.')) {
  918. X        if (*n != *t && *t != '?') {    /* match fail? */
  919. X            if (*t != '*')    /* wildcard fail? */
  920. X                return 0;    /* then no match */
  921. X            else {    /* else jump over wildcard */
  922. X                while (*n && *n != '.')
  923. X                    n++;
  924. X                while (*t && *t != '.')
  925. X                    t++;
  926. X                break;    /* name part matches wildcard */
  927. X            }
  928. X        } else {    /* match good for this char */
  929. X            n++;    /* advance to next char */
  930. X            t++;
  931. X        }
  932. X    }
  933. X
  934. X    if (*n && *n == '.')
  935. X        n++;        /* skip extension delimiters */
  936. X    if (*t && *t == '.')
  937. X        t++;
  938. X
  939. X    /* now match name part */
  940. X
  941. X    while (*n || *t) {
  942. X        if (*n != *t && *t != '?') {    /* match fail? */
  943. X            if (*t != '*')    /* wildcard fail? */
  944. X                return 0;    /* then no match */
  945. X            else
  946. X                return 1;    /* else good enough */
  947. X        } else {    /* match good for this char */
  948. X            n++;    /* advance to next char */
  949. X            t++;
  950. X        }
  951. X    }
  952. X
  953. X    return 1;        /* match worked */
  954. X#endif    /* GEMDOS */
  955. X}
  956. X#endif
  957. X
  958. Xvoid
  959. Xrempath(nargs, arg)        /* remove paths from filenames */
  960. X    int             nargs;    /* number of names */
  961. X    char           *arg[];    /* pointers to names */
  962. X{
  963. X    char           *i, *rindex();    /* string index, reverse indexer */
  964. X    int             n;    /* index */
  965. X
  966. X    for (n = 0; n < nargs; n++) {    /* for each supplied name */
  967. X        if (!(i = rindex(arg[n], '\\')))    /* search for end of
  968. X                             * path */
  969. X            if (!(i = rindex(arg[n], '/')))
  970. X                i = rindex(arg[n], ':');
  971. X        if (i)        /* if path was found */
  972. X            arg[n] = i + 1;    /* then skip it */
  973. X    }
  974. X}
  975. ________This_Is_The_END________
  976. if test `wc -c < arcmatch.c` -ne     3026; then
  977.     echo 'shar: arcmatch.c was damaged during transit (should have been     3026 bytes)'
  978. fi
  979. fi        ; : end of overwriting check
  980. echo 'x - arcmisc.c'
  981. if test -f arcmisc.c; then echo 'shar: not overwriting arcmisc.c'; else
  982. sed 's/^X//' << '________This_Is_The_END________' > arcmisc.c
  983. X/*
  984. X * Miscellaneous routines to get ARC running on non-MSDOS systems...
  985. X * $Header: arcmisc.c,v 1.7 88/06/12 19:23:13 hyc Locked $ 
  986. X */
  987. X
  988. X#include <stdio.h>
  989. X#include <ctype.h>
  990. X#include "arc.h"
  991. X
  992. X#if    MSDOS
  993. X#include <dir.h>
  994. X#include <stat.h>
  995. X#endif
  996. X
  997. X#if    GEMDOS
  998. X#include <osbind.h>
  999. X#include <stat.h>
  1000. Xchar           *index(), *rindex();
  1001. X
  1002. Xvoid 
  1003. Xexitpause()
  1004. X{
  1005. X    while (Cconis())
  1006. X        Cnecin();
  1007. X    fprintf(stderr, "Press any key to continue: ");
  1008. X    fflush(stderr);
  1009. X    Cnecin();
  1010. X    fprintf(stderr, "\n");
  1011. X}
  1012. X
  1013. Xint
  1014. Xchdir(dirname)
  1015. X    char           *dirname;
  1016. X{
  1017. X    char           *i;
  1018. X    int             drv;
  1019. X
  1020. X    i = dirname;
  1021. X    if ((i = index(dirname, ':')) != NULL) {
  1022. X        drv = i[-1];
  1023. X        i++;        /* Move past device spec */
  1024. X        if (drv > '\'')
  1025. X            drv -= 'a';
  1026. X        else
  1027. X            drv -= 'A';
  1028. X        if (drv >= 0 && drv < 16)
  1029. X            Dsetdrv(drv);
  1030. X    }
  1031. X    if (*i != '\0')
  1032. X        return (Dsetpath(i));
  1033. X}
  1034. X#endif
  1035. X
  1036. X#if    UNIX
  1037. X#include <sys/types.h>
  1038. X#include <sys/dir.h>
  1039. X#include <sys/stat.h>
  1040. X    int    rename();
  1041. X#endif
  1042. X
  1043. X#if    SYSV
  1044. X#include <dirent.h>
  1045. X#define DIRECT dirent
  1046. X#else
  1047. X#define DIRECT direct
  1048. X#endif
  1049. X
  1050. Xchar           *strcpy(), *strcat(), *malloc();
  1051. Xint             strlen();
  1052. X
  1053. Xint
  1054. Xmove(oldnam, newnam)
  1055. X    char           *oldnam, *newnam;
  1056. X{
  1057. X    FILE           *fopen(), *old, *new;
  1058. X    struct stat     oldstat;
  1059. X    char           *strcpy();
  1060. X    void        filecopy();
  1061. X#if    GEMDOS
  1062. X    if (Frename(0, oldnam, newnam))
  1063. X#else
  1064. X    if (rename(oldnam, newnam))
  1065. X#endif
  1066. X    {
  1067. X        if (stat(oldnam, &oldstat))    /* different partition? */
  1068. X            return (-1);
  1069. X        old = fopen(oldnam, "rb");
  1070. X        if (old == NULL)
  1071. X            return (-1);
  1072. X        new = fopen(newnam, "wb");
  1073. X        if (new == NULL)
  1074. X            return (-1);
  1075. X        filecopy(old, new, oldstat.st_size);
  1076. X        unlink(oldnam);
  1077. X    }
  1078. X    return 0;
  1079. X}
  1080. X
  1081. Xstatic void
  1082. X_makefn(source, dest)
  1083. X    char           *source;
  1084. X    char           *dest;
  1085. X{
  1086. X    int             j;
  1087. X#if    MSDOS
  1088. X    char           *setmem();
  1089. X#else
  1090. X    char           *memset();
  1091. X#endif
  1092. X
  1093. X    setmem(dest, 17, 0);    /* clear result field */
  1094. X    for (j = 0; *source && *source != '.'; ++source)
  1095. X        if (j < 8)
  1096. X            dest[j++] = *source;
  1097. X    for (j = 9; *source; ++source)
  1098. X        if (j < 13)
  1099. X            dest[j++] = *source;
  1100. X}
  1101. X/*
  1102. X * make a file name using a template 
  1103. X */
  1104. X
  1105. Xchar           *
  1106. Xmakefnam(rawfn, template, result)
  1107. X    char           *rawfn;    /* the original file name */
  1108. X    char           *template;    /* the template data */
  1109. X    char           *result;    /* where to place the result */
  1110. X{
  1111. X    char            et[17], er[17], rawbuf[STRLEN], *i, *rindex();
  1112. X
  1113. X    *rawbuf = 0;
  1114. X    strcpy(rawbuf, rawfn);
  1115. X#if    MTS
  1116. X    i = rawbuf;
  1117. X    if (rawbuf[0] == tmpchr[0]) {
  1118. X        i++;
  1119. X        strcpy(rawfn, i);
  1120. X    } else
  1121. X#endif
  1122. X    if ((i = rindex(rawbuf, CUTOFF))) {
  1123. X        i++;
  1124. X        strcpy(rawfn, i);
  1125. X    }
  1126. X#if    DOS
  1127. X    else if ((i = rindex(rawbuf, ':'))) {
  1128. X        i++;
  1129. X        strcpy(rawfn, i);
  1130. X    }
  1131. X#endif
  1132. X    if (i)
  1133. X        *i = 0;
  1134. X    else
  1135. X        *rawbuf = 0;
  1136. X
  1137. X    _makefn(template, et);
  1138. X    _makefn(rawfn, er);
  1139. X    *result = 0;        /* assure no data */
  1140. X    strcat(result, rawbuf);
  1141. X    strcat(result, er[0] ? er : et);
  1142. X    strcat(result, er[9] ? er + 9 : et + 9);
  1143. X    return ((char *) &result[0]);
  1144. X}
  1145. X
  1146. X#if    MSDOS || SYSV
  1147. X
  1148. Xint
  1149. Xalphasort(dirptr1, dirptr2)
  1150. X    struct DIRECT **dirptr1, **dirptr2;
  1151. X{
  1152. X    return (strcmp((*dirptr1)->d_name, (*dirptr2)->d_name));
  1153. X}
  1154. X
  1155. X#endif
  1156. X
  1157. Xvoid
  1158. Xupper(string)
  1159. X    char           *string;
  1160. X{
  1161. X    char           *p;
  1162. X
  1163. X    for (p = string; *p; p++)
  1164. X        if (islower(*p))
  1165. X            *p = toupper(*p);
  1166. X}
  1167. X/* VARARGS1 */
  1168. Xvoid
  1169. Xabort(s, arg1, arg2, arg3)
  1170. X    char           *s;
  1171. X{
  1172. X    fprintf(stderr, "ARC: ");
  1173. X    fprintf(stderr, s, arg1, arg2, arg3);
  1174. X    fprintf(stderr, "\n");
  1175. X#if    UNIX
  1176. X    perror("UNIX");
  1177. X#endif
  1178. X#if    GEMDOS
  1179. X    exitpause();
  1180. X#endif
  1181. X    exit(1);
  1182. X}
  1183. X
  1184. X#if    !MTS
  1185. X
  1186. Xchar           *
  1187. Xgcdir(dirname)
  1188. X    char           *dirname;
  1189. X
  1190. X{
  1191. X    char           *getwd();
  1192. X#if    GEMDOS
  1193. X    int             drv;
  1194. X    char           *buf;
  1195. X#endif
  1196. X    if (dirname == NULL || strlen(dirname) == 0)
  1197. X        dirname = (char *) malloc(1024);
  1198. X
  1199. X#if    !GEMDOS
  1200. X    getwd(dirname);
  1201. X#else
  1202. X    buf = dirname;
  1203. X    *buf++ = (drv = Dgetdrv()) + 'A';
  1204. X    *buf++ = ':';
  1205. X    Dgetpath(buf, 0);
  1206. X#endif
  1207. X    return (dirname);
  1208. X}
  1209. X
  1210. X#if    UNIX
  1211. Xchar           *pattern;    /* global so that fmatch can use it */
  1212. X#endif
  1213. X
  1214. Xchar           *
  1215. Xdir(filename)        /* get files, one by one */
  1216. X    char           *filename;    /* template, or NULL */
  1217. X{
  1218. X#if    GEMDOS
  1219. X    static int      Nnum = 0;
  1220. X    static DMABUFFER dbuf, *saved;
  1221. X    char           *name;
  1222. X
  1223. X    if (Nnum == 0) {    /* first call */
  1224. X        saved = (DMABUFFER *) Fgetdta();
  1225. X        Fsetdta(&dbuf);
  1226. X        if (Fsfirst(filename, 0) == 0) {
  1227. X            name = malloc(FNLEN);
  1228. X            strcpy(name, dbuf.d_fname);
  1229. X            Nnum++;
  1230. X            return (name);
  1231. X        } else {
  1232. X            Fsetdta(saved);
  1233. X            return (NULL);
  1234. X        }
  1235. X    } else {
  1236. X        if (Fsnext() == 0) {
  1237. X            name = malloc(FNLEN);
  1238. X            strcpy(name, dbuf.d_fname);
  1239. X            return (name);
  1240. X        } else {
  1241. X            Nnum = 0;
  1242. X            Fsetdta(saved);
  1243. X            return (NULL);
  1244. X        }
  1245. X    }
  1246. X}
  1247. X#else
  1248. X    static struct DIRECT **namelist;
  1249. X    static char   **NameList;
  1250. X    static char    namecopy[STRLEN], *dirname;
  1251. X#if    UNIX
  1252. X    int             alphasort();
  1253. X    int             scandir();
  1254. X#endif                /* UNIX */
  1255. X    int             fmatch();
  1256. X    static int      Nnum = 0, ii;
  1257. X    char        *rindex();
  1258. X
  1259. X
  1260. X    if (Nnum == 0) {    /* first call */
  1261. X        strcpy(namecopy,filename);
  1262. X        if(pattern=rindex(namecopy,CUTOFF)) {
  1263. X            *pattern = 0;
  1264. X            pattern++;
  1265. X            dirname = namecopy;
  1266. X        } else {
  1267. X            pattern = filename;
  1268. X            dirname = ".";
  1269. X        }
  1270. X        Nnum = scandir(dirname, &namelist, fmatch, alphasort);
  1271. X        NameList = (char **) malloc(Nnum * sizeof(char *));
  1272. X        for (ii = 0; ii < Nnum; ii++) {
  1273. X            (NameList)[ii] = malloc(strlen(namelist[ii]->d_name) + 1);
  1274. X            strcpy((NameList)[ii], namelist[ii]->d_name);
  1275. X        }
  1276. X        ii = 0;
  1277. X    }
  1278. X    if (ii >= Nnum) {    /* all out of files */
  1279. X        if (Nnum) {    /* there were some files found */
  1280. X            for (ii = 0; ii < Nnum; ii++)
  1281. X                free(namelist[ii]);
  1282. X            free(namelist);
  1283. X        }
  1284. X        Nnum = 0;
  1285. X        return (NULL);
  1286. X    } else {
  1287. X        return ((NameList)[ii++]);
  1288. X    }
  1289. X}
  1290. X
  1291. X/*
  1292. X * Filename match - here, * matches everything 
  1293. X */
  1294. X
  1295. Xint
  1296. Xfmatch(direntry)
  1297. X    struct DIRECT  *direntry;
  1298. X{
  1299. X    char           *string;
  1300. X
  1301. X    string = direntry->d_name;
  1302. X
  1303. X    if (!strcmp(pattern, "") || !strcmp(pattern, "*.*") || !strcmp(pattern, "*"))
  1304. X        return (1);
  1305. X    return (match(string, pattern));
  1306. X}
  1307. X#endif                /* GEMDOS */
  1308. X#else
  1309. X/* dir code for MTS under Bell Labs C... */
  1310. X
  1311. Xchar           *
  1312. Xdir(filepattern)
  1313. X    char           *filepattern;    /* template or NULL */
  1314. X{
  1315. X    char           *malloc(), *index();
  1316. X#if    USECATSCAN
  1317. X    fortran void    catscan(), fileinfo();
  1318. X
  1319. X    struct catname {
  1320. X        short           len;
  1321. X        char            name[257];
  1322. X    }               pattern;
  1323. X
  1324. X    struct catval {
  1325. X        int             maxlen;
  1326. X        int             actlen;
  1327. X        char            name[257];
  1328. X    }               catreturn;
  1329. X
  1330. X    char           *i;
  1331. X    int             j, RETCODE;
  1332. X
  1333. X    static int      catptr = 0;
  1334. X    static int      catflag = 0x200;
  1335. X    static int      cattype = 1;
  1336. X    static int      patflag = 0;
  1337. X
  1338. X    catreturn.maxlen = 256;
  1339. X
  1340. X    if (patflag) {
  1341. X        patflag = 0;
  1342. X        catptr = 0;
  1343. X        return (NULL);
  1344. X    }
  1345. X    if (filepattern) {
  1346. X        strcpy(pattern.name, filepattern);
  1347. X        pattern.len = strlen(filepattern);
  1348. X        if (!index(filepattern, '?'))
  1349. X            patflag = 1;
  1350. X    }
  1351. X    if (patflag) {
  1352. X        fileinfo(&pattern, &cattype, "CINAME  ", &catreturn, _retcode RETCODE);
  1353. X        catptr = RETCODE ? 0 : 1;
  1354. X    } else
  1355. X        catscan(&pattern, &catflag, &cattype, &catreturn, &catptr);
  1356. X
  1357. X    if (!catptr)
  1358. X        return (NULL);
  1359. X    else {
  1360. X        char           *k;
  1361. X
  1362. X        k = index(catreturn.name, ' ');
  1363. X        if (k)
  1364. X            *k = 0;
  1365. X        else {
  1366. X            j = catreturn.actlen;
  1367. X            catreturn.name[j] = 0;
  1368. X        }
  1369. X        k = catreturn.name;
  1370. X        if (catreturn.name[0] == tmpchr[0])
  1371. X            k++;
  1372. X        else if ((k = index(catreturn.name, sepchr[0])))
  1373. X            k++;
  1374. X        else
  1375. X            k = catreturn.name;
  1376. X        j = strlen(k);
  1377. X        i = malloc(++j);
  1378. X        strcpy(i, k);
  1379. X        return (i);
  1380. X    }
  1381. X#else
  1382. X    fortran void    gfinfo();
  1383. X    static char     gfname[24];
  1384. X    static char     pattern[20];
  1385. X    static int      gfdummy[2] = {
  1386. X                      0, 0
  1387. X    },              gfflags;
  1388. X    int             i, RETCODE;
  1389. X    char           *j, *k;
  1390. X
  1391. X    if (filepattern) {
  1392. X        strcpy(pattern, filepattern);
  1393. X        strcat(pattern, " ");
  1394. X        for (i = 20; i < 24; i++)
  1395. X            gfname[i] = '\0';
  1396. X        if (index(pattern, '?'))
  1397. X            gfflags = 0x0C;
  1398. X        else
  1399. X            gfflags = 0x09;
  1400. X    } else if (gfflags == 0x09)
  1401. X        return (NULL);
  1402. X
  1403. X    gfinfo(pattern, gfname, &gfflags, gfdummy, gfdummy, gfdummy, _retcode RETCODE);
  1404. X    if (RETCODE)
  1405. X        return (NULL);
  1406. X    else {
  1407. X        k = index(gfname, ' ');
  1408. X        *k = '\0';
  1409. X        k = gfname;
  1410. X        if (gfname[0] == tmpchr[0])
  1411. X            k++;
  1412. X        else if ((k = index(gfname, sepchr[0])))
  1413. X            k++;
  1414. X        else
  1415. X            k = gfname;
  1416. X        i = strlen(k);
  1417. X        j = malloc(++i);
  1418. X        strcpy(j, k);
  1419. X        return (j);
  1420. X    }
  1421. X#endif
  1422. X}
  1423. X
  1424. Xint
  1425. Xunlink(path)
  1426. X    char           *path;    /* name of file to delete */
  1427. X{
  1428. X    fortran void    destroy();
  1429. X    int             RETCODE;
  1430. X
  1431. X    char            name[258];
  1432. X
  1433. X    strcpy(name, path);
  1434. X    strcat(name, " ");
  1435. X    destroy(name, _retcode RETCODE);
  1436. X    if (RETCODE)
  1437. X        return (-1);
  1438. X    else
  1439. X        return (0);
  1440. X}
  1441. X#endif
  1442. ________This_Is_The_END________
  1443. if test `wc -c < arcmisc.c` -ne     8418; then
  1444.     echo 'shar: arcmisc.c was damaged during transit (should have been     8418 bytes)'
  1445. fi
  1446. fi        ; : end of overwriting check
  1447. echo 'x - arcpack.c'
  1448. if test -f arcpack.c; then echo 'shar: not overwriting arcpack.c'; else
  1449. sed 's/^X//' << '________This_Is_The_END________' > arcpack.c
  1450. X/*
  1451. X * $Header: arcpack.c,v 1.9 88/06/02 16:27:36 hyc Locked $
  1452. X */
  1453. X
  1454. X/*  ARC - Archive utility - ARCPACK
  1455. X
  1456. X    Version 3.49, created on 04/21/87 at 11:26:51
  1457. X
  1458. X(C) COPYRIGHT 1985-87 by System Enhancement Associates; ALL RIGHTS RESERVED
  1459. X
  1460. X    By:     Thom Henderson
  1461. X
  1462. X    Description:
  1463. X     This file contains the routines used to compress a file
  1464. X     when placing it in an archive.
  1465. X
  1466. X    Language:
  1467. X     Computer Innovations Optimizing C86
  1468. X*/
  1469. X#include <stdio.h>
  1470. X#include "arc.h"
  1471. X#if    MTS
  1472. X#include <ctype.h>
  1473. X#endif
  1474. X
  1475. Xvoid    setcode(), sqinit_cm(), sqputc_cm(), init_cm(), putc_cm();
  1476. Xvoid    filecopy(), abort(), putc_tst();
  1477. Xint    getch(), addcrc();
  1478. X
  1479. X/* stuff for non-repeat packing */
  1480. X
  1481. X#define DLE 0x90        /* repeat sequence marker */
  1482. X
  1483. Xstatic unsigned char state;    /* current packing state */
  1484. X
  1485. X/* non-repeat packing states */
  1486. X
  1487. X#define NOHIST  0        /* don't consider previous input */
  1488. X#define SENTCHAR 1        /* lastchar set, no lookahead yet */
  1489. X#define SENDNEWC 2        /* run over, send new char next */
  1490. X#define SENDCNT 3        /* newchar set, send count next */
  1491. X
  1492. X/* packing results */
  1493. X
  1494. Xstatic long     stdlen;        /* length for standard packing */
  1495. Xstatic short    crcval;        /* CRC check value */
  1496. X
  1497. Xvoid
  1498. Xpack(f, t, hdr)            /* pack file into an archive */
  1499. X    FILE           *f, *t;    /* source, destination */
  1500. X    struct heads   *hdr;    /* pointer to header data */
  1501. X{
  1502. X    int             c;    /* one character of stream */
  1503. X    long            ncrlen;    /* length after packing */
  1504. X    long        huflen;    /* length after squeezing */
  1505. X    long            lzwlen;    /* length after crunching */
  1506. X    long        pred_sq(), file_sq();    /* stuff for squeezing */
  1507. X    long            pred_cm(), sqpred_cm();    /* dynamic crunching cleanup */
  1508. X    long            tloc, ftell();    /* start of output */
  1509. X    int        getch();
  1510. X    int             getc_ncr();
  1511. X    void            putc_pak();
  1512. X
  1513. X    /* first pass - see which method is best */
  1514. X
  1515. X    tloc = ftell(t);    /* note start of output */
  1516. X
  1517. X    if (!nocomp) {        /* if storage kludge not active */
  1518. X        if (note) {
  1519. X            printf(" analyzing, ");
  1520. X            fflush(stdout);
  1521. X        }
  1522. X        state = NOHIST;    /* initialize ncr packing */
  1523. X        stdlen = ncrlen = 0;    /* reset size counters */
  1524. X        crcval = 0;    /* initialize CRC check value */
  1525. X        setcode();    /* initialize encryption */
  1526. X        init_sq();    /* initialize for squeeze scan */
  1527. X
  1528. X        if (dosquash) {
  1529. X            sqinit_cm();
  1530. X            while ((c = getch(f)) != EOF) {    /* for each byte of file */
  1531. X                ncrlen++;    /* one more packed byte */
  1532. X                scan_sq(c);    /* see what squeezing can do */
  1533. X                sqputc_cm(c, t);    /* see what squashing
  1534. X                             * can do */
  1535. X            }
  1536. X            lzwlen = sqpred_cm(t);
  1537. X        } else {
  1538. X            init_cm(t);    /* initialize for crunching */
  1539. X    
  1540. X            while ((c = getc_ncr(f)) != EOF) {    /* for each byte of file */
  1541. X                ncrlen++;    /* one more packed byte */
  1542. X                scan_sq(c);    /* see what squeezing can do */
  1543. X                putc_cm(c, t);    /* see what crunching can do */
  1544. X            }
  1545. X            lzwlen = pred_cm(t);    /* finish up after crunching */
  1546. X        }
  1547. X        huflen = pred_sq();    /* finish up after squeezing */
  1548. X    } else {        /* else kludge the method */
  1549. X        stdlen = 0;    /* make standard look best */
  1550. X        ncrlen = huflen = lzwlen = 1;
  1551. X    }
  1552. X
  1553. X    /* standard set-ups common to all methods */
  1554. X
  1555. X    fseek(f, 0L, 0);    /* rewind input */
  1556. X    hdr->crc = crcval;    /* note CRC check value */
  1557. X    hdr->length = stdlen;    /* set actual file length */
  1558. X    state = NOHIST;        /* reinitialize ncr packing */
  1559. X    setcode();        /* reinitialize encryption */
  1560. X
  1561. X    /* choose and use the shortest method */
  1562. X
  1563. X    if (kludge && note)
  1564. X        printf("\n\tS:%ld  P:%ld  S:%ld  C:%ld,\t ",
  1565. X            stdlen, ncrlen, huflen, lzwlen);
  1566. X
  1567. X    if (stdlen <= ncrlen && stdlen <= huflen && stdlen <= lzwlen) {
  1568. X        if (note) {
  1569. X            printf("storing, ");    /* store without compression */
  1570. X            fflush(stdout);
  1571. X        }
  1572. X        hdrver = 2;    /* note packing method */
  1573. X        fseek(t, tloc, 0);    /* reset output for new method */
  1574. X        stdlen = crcval = 0;    /* recalc these for kludge */
  1575. X        while ((c = getch(f)) != EOF)    /* store it straight */
  1576. X            putc_pak(c, t);
  1577. X        hdr->crc = crcval;
  1578. X        hdr->length = hdr->size = stdlen;
  1579. X    } else if (ncrlen < lzwlen && ncrlen < huflen) {
  1580. X        if (note) {
  1581. X            printf("packing, ");    /* pack with repeat
  1582. X            fflush(stdout);         * suppression */
  1583. X        }
  1584. X        hdrver = 3;    /* note packing method */
  1585. X        hdr->size = ncrlen;    /* set data length */
  1586. X        fseek(t, tloc, 0);    /* reset output for new method */
  1587. X        while ((c = getc_ncr(f)) != EOF)
  1588. X            putc_pak(c, t);
  1589. X    } else if (huflen < lzwlen) {
  1590. X        if (note) {
  1591. X            printf("squeezing, ");
  1592. X            fflush(stdout);
  1593. X        }
  1594. X        hdrver = 4;    /* note packing method */
  1595. X        fseek(t, tloc, 0);    /* reset output for new method */
  1596. X        hdr->size = file_sq(f, t);    /* note final size */
  1597. X    } else {
  1598. X        if (note)
  1599. X            printf(dosquash ? "squashed, " : "crunched, ");
  1600. X        hdrver = dosquash ? 9 : 8;
  1601. X        hdr->size = lzwlen;    /* size should not change */
  1602. X    }
  1603. X
  1604. X    /* standard cleanups common to all methods */
  1605. X
  1606. X    if (note)
  1607. X        printf("done. (%ld%%)\n",100L - (100L*hdr->size)/hdr->length);
  1608. X}
  1609. X
  1610. X/*
  1611. X * Non-repeat compression - text is passed through normally, except that a
  1612. X * run of more than two is encoded as:
  1613. X * 
  1614. X * <char> <DLE> <count>
  1615. X * 
  1616. X * Special case: a count of zero indicates that the DLE is really a DLE, not a
  1617. X * repeat marker.
  1618. X */
  1619. X
  1620. Xint
  1621. Xgetc_ncr(f)            /* get bytes with collapsed runs */
  1622. X    FILE           *f;    /* file to get from */
  1623. X{
  1624. X    static int      lastc;    /* value returned on last call */
  1625. X    static int      repcnt;    /* repetition counter */
  1626. X    static int      c;    /* latest value seen */
  1627. X
  1628. X    switch (state) {    /* depends on our state */
  1629. X    case NOHIST:        /* no relevant history */
  1630. X        state = SENTCHAR;
  1631. X        return lastc = getch(f);    /* remember the value next
  1632. X                         * time */
  1633. X
  1634. X    case SENTCHAR:        /* char was sent. look ahead */
  1635. X        switch (lastc) {/* action depends on char */
  1636. X        case DLE:    /* if we sent a real DLE */
  1637. X            state = NOHIST;    /* then start over again */
  1638. X            return 0;    /* but note that the DLE was real */
  1639. X
  1640. X        case EOF:    /* EOF is always a special case */
  1641. X            return EOF;
  1642. X
  1643. X        default:    /* else test for a repeat */
  1644. X            for (repcnt = 1; (c = getch(f)) == lastc && repcnt < 255; repcnt++);
  1645. X            /* find end of run */
  1646. X
  1647. X            switch (repcnt) {    /* action depends on run size */
  1648. X            case 1:/* not a repeat */
  1649. X                return lastc = c;    /* but remember value
  1650. X                             * next time */
  1651. X
  1652. X            case 2:/* a repeat, but too short */
  1653. X                state = SENDNEWC;    /* send the second one
  1654. X                             * next time */
  1655. X                return lastc;
  1656. X
  1657. X            default:    /* a run - compress it */
  1658. X                state = SENDCNT;    /* send repeat count
  1659. X                             * next time */
  1660. X                return DLE;    /* send repeat marker this
  1661. X                         * time */
  1662. X            }
  1663. X        }
  1664. X
  1665. X    case SENDNEWC:        /* send second char of short run */
  1666. X        state = SENTCHAR;
  1667. X        return lastc = c;
  1668. X
  1669. X    case SENDCNT:        /* sent DLE, now send count */
  1670. X        state = SENDNEWC;
  1671. X        return repcnt;
  1672. X
  1673. X    default:
  1674. X        abort("Bug - bad ncr state\n");
  1675. X    }
  1676. X}
  1677. X
  1678. Xint
  1679. Xgetch(f)            /* special get char for packing */
  1680. X    FILE           *f;    /* file to get from */
  1681. X{
  1682. X    int        c;    /* a char from the file */
  1683. X#if    !DOS
  1684. X    static int      cr = 0;    /* add \r before \n ? */
  1685. X
  1686. X    if (cr) {
  1687. X        c = '\n';
  1688. X#if    MTS
  1689. X        c = toascii(c);
  1690. X#endif
  1691. X        crcval = addcrc(crcval, c);
  1692. X        stdlen++;
  1693. X        cr = 0;
  1694. X        return (c);
  1695. X    }
  1696. X#endif
  1697. X
  1698. X    if ((c = fgetc(f)) != EOF) {    /* if not the end of file */
  1699. X#if    !DOS
  1700. X        if (!image && (c == '\n')) {
  1701. X            c = '\r';
  1702. X            cr = 1;
  1703. X        }
  1704. X#endif
  1705. X#if    MTS
  1706. X        if (!image)
  1707. X            c = toascii(c);
  1708. X#endif
  1709. X        crcval = addcrc(crcval, c);    /* then update CRC check
  1710. X                         * value */
  1711. X        stdlen++;    /* and bump length counter */
  1712. X    }
  1713. X    return c;
  1714. X}
  1715. X
  1716. Xvoid
  1717. Xputc_pak(c, f)            /* put a packed byte into archive */
  1718. X    char            c;    /* byte to put */
  1719. X    FILE           *f;    /* archive to put it in */
  1720. X{
  1721. X    unsigned char        code();
  1722. X    putc_tst(code(c), f);    /* put encoded byte, with checks */
  1723. X}
  1724. ________This_Is_The_END________
  1725. if test `wc -c < arcpack.c` -ne     7376; then
  1726.     echo 'shar: arcpack.c was damaged during transit (should have been     7376 bytes)'
  1727. fi
  1728. fi        ; : end of overwriting check
  1729. echo 'x - arcrun.c'
  1730. if test -f arcrun.c; then echo 'shar: not overwriting arcrun.c'; else
  1731. sed 's/^X//' << '________This_Is_The_END________' > arcrun.c
  1732. X/*
  1733. X * $Header: arcrun.c,v 1.3 88/06/01 19:57:16 hyc Locked $
  1734. X */
  1735. X
  1736. X/*
  1737. X * ARC - Archive utility - ARCRUN
  1738. X * 
  1739. X * Version 1.20, created on 03/24/86 at 19:34:31
  1740. X * 
  1741. X * (C) COPYRIGHT 1985,85 by System Enhancement Associates; ALL RIGHTS RESERVED
  1742. X * 
  1743. X * By:  Thom Henderson
  1744. X * 
  1745. X * Description: This file contains the routines used to "run" a file which is
  1746. X * stored in an archive.  At present, all we really do is (a) extract a
  1747. X * temporary file, (b) give its name as a system command, and then (c) delete
  1748. X * the file.
  1749. X * 
  1750. X * Language: Computer Innovations Optimizing C86
  1751. X */
  1752. X#include <stdio.h>
  1753. X#include "arc.h"
  1754. X
  1755. Xvoid    rempath(), openarc(), closearc(), abort();
  1756. Xchar    *strcat();
  1757. X
  1758. Xvoid
  1759. Xrunarc(num, arg)        /* run file from archive */
  1760. X    int             num;    /* number of arguments */
  1761. X    char           *arg[];    /* pointers to arguments */
  1762. X{
  1763. X    struct heads    hdr;    /* file header */
  1764. X    char           *makefnam();    /* filename fixer */
  1765. X    char            buf[STRLEN];    /* filename buffer */
  1766. X    FILE           *fopen();/* file opener */
  1767. X    int             runfile();
  1768. X    char           *dummy[2];
  1769. X
  1770. X    dummy[0]="dummy";
  1771. X    dummy[1]=NULL;
  1772. X    rempath(num, arg);    /* strip off paths */
  1773. X
  1774. X    openarc(0);        /* open archive for reading */
  1775. X
  1776. X    if (num) {        /* if files were named */
  1777. X        while (readhdr(&hdr, arc)) {    /* while more files to check */
  1778. X            if (match(hdr.name, makefnam(arg[0], ".*", buf)))
  1779. X                runfile(&hdr, num, arg);
  1780. X            else
  1781. X                fseek(arc, hdr.size, 1);
  1782. X        }
  1783. X    } else
  1784. X        while (readhdr(&hdr, arc))    /* else run all files */
  1785. X            runfile(&hdr, 1, dummy);
  1786. X
  1787. X    closearc(0);        /* close archive after changes */
  1788. X}
  1789. X
  1790. Xstatic          int
  1791. Xrunfile(hdr, num, arg)        /* run a file */
  1792. X    struct heads   *hdr;    /* pointer to header data */
  1793. X    int             num;    /* number of arguments */
  1794. X    char           *arg[];    /* pointers to arguments */
  1795. X{
  1796. X    FILE           *tmp, *fopen();    /* temporary file */
  1797. X    char           *dir, *gcdir();    /* directory stuff */
  1798. X    char            buf[STRLEN], *makefnam();    /* temp file name, fixer */
  1799. X#if    DOS
  1800. X    char        nbuf[64], *i, *rindex();
  1801. X#endif
  1802. X#if    !GEMDOS
  1803. X    int             n;    /* index */
  1804. X    char            sys[STRLEN];    /* invocation command buffer */
  1805. X#endif
  1806. X
  1807. X    /* makefnam("$ARCTEMP",hdr->name,buf); */
  1808. X#if    UNIX
  1809. X    sprintf(buf, "%s.RUN", arctemp);
  1810. X    strcpy(sys, buf);
  1811. X#else
  1812. X    strcpy(nbuf, arctemp);
  1813. X    makefnam(nbuf,hdr->name,buf);
  1814. X    i = rindex(buf,'.');
  1815. X#endif
  1816. X#if    MSDOS
  1817. X    if (!strcmp(i, ".BAS")) {
  1818. X        strcpy(sys, "BASICA ");
  1819. X        strcat(sys, buf);
  1820. X    }
  1821. X    else if (!strcmp(i, ".BAT")
  1822. X         || !strcmp(i, ".COM")
  1823. X         || !strcmp(i, ".EXE"))
  1824. X        strcpy(sys, buf);
  1825. X
  1826. X    else {
  1827. X        if (warn) {
  1828. X            printf("File %s is not a .BAS, .BAT, .COM, or .EXE\n",
  1829. X                   hdr->name);
  1830. X            nerrs++;
  1831. X        }
  1832. X        fseek(arc, hdr->size, 1);    /* skip this file */
  1833. X        return;
  1834. X    }
  1835. X#endif
  1836. X#if    GEMDOS
  1837. X      if (strcmp(i, ".PRG")
  1838. X              && strcmp(i, ".TTP")
  1839. X              && strcmp(i, ".TOS"))
  1840. X      {
  1841. X              if (warn) {
  1842. X                      printf("File %s is not a .PRG, .TOS, or .TTP\n",
  1843. X                              hdr->name);
  1844. X                      nerrs++;
  1845. X              }
  1846. X              fseek(arc, hdr->size, 1);       /* skip this file */
  1847. X              return;
  1848. X      }
  1849. X#endif
  1850. X
  1851. X    if (warn)
  1852. X        if (tmp = fopen(buf, "r"))
  1853. X            abort("Temporary file %s already exists", buf);
  1854. X    if (!(tmp = fopen(buf, "wb")))
  1855. X        abort("Unable to create temporary file %s", buf);
  1856. X
  1857. X    if (note)
  1858. X        printf("Invoking file: %s\n", hdr->name);
  1859. X
  1860. X    dir = gcdir("");    /* see where we are */
  1861. X    unpack(arc, tmp, hdr);    /* unpack the entry */
  1862. X    fclose(tmp);        /* release the file */
  1863. X    chmod(buf, "700");    /* make it executable */
  1864. X#if    GEMDOS
  1865. X    execve(buf, arg, NULL);
  1866. X#else
  1867. X    for (n = 1; n < num; n++) {    /* add command line arguments */
  1868. X        strcat(sys, " ");
  1869. X        strcat(sys, arg[n]);
  1870. X    }
  1871. X    system(buf);        /* try to invoke it */
  1872. X#endif
  1873. X    chdir(dir);
  1874. X    free(dir);        /* return to whence we started */
  1875. X    if (unlink(buf) && warn) {
  1876. X        printf("Cannot unsave temporary file %s\n", buf);
  1877. X        nerrs++;
  1878. X    }
  1879. X}
  1880. ________This_Is_The_END________
  1881. if test `wc -c < arcrun.c` -ne     3838; then
  1882.     echo 'shar: arcrun.c was damaged during transit (should have been     3838 bytes)'
  1883. fi
  1884. fi        ; : end of overwriting check
  1885. echo 'x - arcs.h'
  1886. if test -f arcs.h; then echo 'shar: not overwriting arcs.h'; else
  1887. sed 's/^X//' << '________This_Is_The_END________' > arcs.h
  1888. X/*
  1889. X * $Header: arcs.h,v 1.2 88/04/17 18:53:19 hyc Exp $
  1890. X */
  1891. X
  1892. X/*
  1893. X * ARC - Archive utility - Archive file header format
  1894. X * 
  1895. X * Version 2.12, created on 12/17/85 at 14:40:26
  1896. X * 
  1897. X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
  1898. X * 
  1899. X * By:  Thom Henderson
  1900. X * 
  1901. X * Description: This file defines the format of an archive file header,
  1902. X * excluding the archive marker and the header version number.
  1903. X * 
  1904. X * Each entry in an archive begins with a one byte archive marker, which is set
  1905. X * to 26.  The marker is followed by a one byte header type code, from zero
  1906. X * to 7.
  1907. X * 
  1908. X * If the header type code is zero, then it is an end marker, and no more data
  1909. X * should be read from the archive.
  1910. X * 
  1911. X * If the header type code is in the range 2 to 7, then it is followed by a
  1912. X * standard archive header, which is defined below.
  1913. X * 
  1914. X * If the header type code is one, then it is followed by an older format
  1915. X * archive header.  The older format header does not contain the true length.
  1916. X * A header should be read for a length of sizeof(struct heads)-sizeof(long).
  1917. X * Then set length equal to size and change the header version to 2.
  1918. X * 
  1919. X * Programming note: The crc value given in the header is based on the unpacked
  1920. X * data.
  1921. X * 
  1922. X * Language: Computer Innovations Optimizing C86
  1923. X */
  1924. X
  1925. Xstruct heads {            /* archive entry header format */
  1926. X    char    name[FNLEN];        /* file name */
  1927. X            long size;        /* size of file, in bytes */
  1928. X    unsigned    short date;    /* creation date */
  1929. X    unsigned    short time;    /* creation time */
  1930. X                short crc;    /* cyclic redundancy check */
  1931. X                long length;    /* true file length */
  1932. X};
  1933. ________This_Is_The_END________
  1934. if test `wc -c < arcs.h` -ne     1645; then
  1935.     echo 'shar: arcs.h was damaged during transit (should have been     1645 bytes)'
  1936. fi
  1937. fi        ; : end of overwriting check
  1938. echo 'x - arcsq.c'
  1939. if test -f arcsq.c; then echo 'shar: not overwriting arcsq.c'; else
  1940. sed 's/^X//' << '________This_Is_The_END________' > arcsq.c
  1941. X/*
  1942. X * $Header: arcsq.c,v 1.2 88/06/02 16:27:38 hyc Locked $
  1943. X */
  1944. X
  1945. X/*
  1946. X * ARC - Archive utility - ARCSQ 
  1947. X *
  1948. X * Version 3.10, created on 01/30/86 at 20:10:46
  1949. X *
  1950. X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED 
  1951. X *
  1952. X * By:  Thom Henderson 
  1953. X *
  1954. X * Description: This file contains the routines used to squeeze a file when
  1955. X * placing it in an archive. 
  1956. X *
  1957. X * Language: Computer Innovations Optimizing C86 
  1958. X *
  1959. X * Programming notes: Most of the routines used for the Huffman squeezing
  1960. X * algorithm were lifted from the SQ program by Dick Greenlaw, as adapted to
  1961. X * CI-C86 by Robert J. Beilstein. 
  1962. X */
  1963. X#include <stdio.h>
  1964. X#include "arc.h"
  1965. X
  1966. X/* stuff for Huffman squeezing */
  1967. X
  1968. X#define TRUE 1
  1969. X#define FALSE 0
  1970. X#define ERROR (-1)
  1971. X#define SPEOF 256        /* special endfile token */
  1972. X#define NOCHILD (-1)        /* marks end of path through tree */
  1973. X#define NUMVALS 257        /* 256 data values plus SPEOF */
  1974. X#define NUMNODES (NUMVALS+NUMVALS-1)    /* number of nodes */
  1975. X#define MAXCOUNT (unsigned short) 65535    /* biggest unsigned integer */
  1976. X
  1977. X/*
  1978. X * The following array of structures are the nodes of the binary trees. The
  1979. X * first NUMVALS nodes become the leaves of the final tree and represent the
  1980. X * values of the data bytes being encoded and the special endfile, SPEOF. The
  1981. X * remaining nodes become the internal nodes of the final tree. 
  1982. X */
  1983. X
  1984. Xstruct nd {            /* shared by unsqueezer */
  1985. X    unsigned short    weight;    /* number of appearances */
  1986. X    short        tdepth;    /* length on longest path in tree */
  1987. X    short        lchild, rchild;    /* indices to next level */
  1988. X}               node[NUMNODES];    /* use large buffer */
  1989. X
  1990. Xstatic int      dctreehd;    /* index to head of final tree */
  1991. X
  1992. X/*
  1993. X * This is the encoding table: The bit strings have first bit in low bit.
  1994. X * Note that counts were scaled so code fits unsigned integer. 
  1995. X */
  1996. X
  1997. Xstatic int      codelen[NUMVALS];    /* number of bits in code */
  1998. Xstatic unsigned short code[NUMVALS];    /* code itself, right adjusted */
  1999. Xstatic unsigned short tcode;    /* temporary code value */
  2000. Xstatic long     valcount[NUMVALS];    /* actual count of times seen */
  2001. X
  2002. X/* Variables used by encoding process */
  2003. X
  2004. Xstatic int      curin;        /* value currently being encoded */
  2005. Xstatic int      cbitsrem;    /* # of code string bits left */
  2006. Xstatic unsigned short ccode;    /* current code right justified */
  2007. X
  2008. Xint 
  2009. Xinit_sq()
  2010. X{                /* prepare for scanning pass */
  2011. X    int             i;    /* node index */
  2012. X
  2013. X    /*
  2014. X     * Initialize all nodes to single element binary trees with zero
  2015. X     * weight and depth. 
  2016. X     */
  2017. X
  2018. X    for (i = 0; i < NUMNODES; ++i) {
  2019. X        node[i].weight = 0;
  2020. X        node[i].tdepth = 0;
  2021. X        node[i].lchild = NOCHILD;
  2022. X        node[i].rchild = NOCHILD;
  2023. X    }
  2024. X
  2025. X    for (i = 0; i < NUMVALS; i++)
  2026. X        valcount[i] = 0;
  2027. X}
  2028. X
  2029. Xint 
  2030. Xscan_sq(c)            /* add a byte to the tables */
  2031. X    int             c;    /* byte to add */
  2032. X{
  2033. X    unsigned short *wp;    /* speeds up weight counting */
  2034. X
  2035. X    /* Build frequency info in tree */
  2036. X
  2037. X    if (c == EOF)        /* it's traditional */
  2038. X        c = SPEOF;    /* dumb, but traditional */
  2039. X
  2040. X    if (*(wp = &node[c].weight) != MAXCOUNT)
  2041. X        ++(*wp);    /* bump weight counter */
  2042. X
  2043. X    valcount[c]++;        /* bump byte counter */
  2044. X}
  2045. X
  2046. Xlong 
  2047. Xpred_sq()
  2048. X{                /* predict size of squeezed file */
  2049. X    int             i;
  2050. X    int             btlist[NUMVALS];    /* list of intermediate
  2051. X                         * b-trees */
  2052. X    int             listlen;/* length of btlist */
  2053. X    unsigned short    ceiling;/* limit for scaling */
  2054. X    long            size = 0;    /* predicted size */
  2055. X    int             numnodes;    /* # of nodes in simplified tree */
  2056. X    int             scale();
  2057. X    int             heap();
  2058. X    int             bld_tree();
  2059. X    int             buildenc();
  2060. X    int             init_enc();
  2061. X
  2062. X    scan_sq(EOF);        /* signal end of input */
  2063. X
  2064. X    ceiling = MAXCOUNT;
  2065. X
  2066. X    /* Keep trying to scale and encode */
  2067. X
  2068. X    do {
  2069. X        scale(ceiling);
  2070. X        ceiling /= 2;    /* in case we rescale */
  2071. X
  2072. X        /*
  2073. X         * Build list of single node binary trees having leaves for
  2074. X         * the input values with non-zero counts 
  2075. X         */
  2076. X
  2077. X        for (i = listlen = 0; i < NUMVALS; ++i) {
  2078. X            if (node[i].weight != 0) {
  2079. X                node[i].tdepth = 0;
  2080. X                btlist[listlen++] = i;
  2081. X            }
  2082. X        }
  2083. X
  2084. X        /*
  2085. X         * Arrange list of trees into a heap with the entry indexing
  2086. X         * the node with the least weight at the top. 
  2087. X         */
  2088. X
  2089. X        heap(btlist, listlen);
  2090. X
  2091. X        /* Convert the list of trees to a single decoding tree */
  2092. X
  2093. X        bld_tree(btlist, listlen);
  2094. X
  2095. X        /* Initialize the encoding table */
  2096. X
  2097. X        init_enc();
  2098. X
  2099. X        /*
  2100. X         * Try to build encoding table. Fail if any code is > 16 bits
  2101. X         * long. 
  2102. X         */
  2103. X    } while (buildenc(0, dctreehd) == ERROR);
  2104. X
  2105. X    /* Initialize encoding variables */
  2106. X
  2107. X    cbitsrem = 0;        /* force initial read */
  2108. X    curin = 0;        /* anything but endfile */
  2109. X
  2110. X    for (i = 0; i < NUMVALS; i++)    /* add bits for each code */
  2111. X        size += valcount[i] * codelen[i];
  2112. X
  2113. X    size = (size + 7) / 8;    /* reduce to number of bytes */
  2114. X
  2115. X    numnodes = dctreehd < NUMVALS ? 0 : dctreehd - (NUMVALS - 1);
  2116. X
  2117. X    size += sizeof(short) + 2 * numnodes * sizeof(short);
  2118. X
  2119. X    return size;
  2120. X}
  2121. X
  2122. X/*
  2123. X * The count of number of occurrances of each input value have already been
  2124. X * prevented from exceeding MAXCOUNT. Now we must scale them so that their
  2125. X * sum doesn't exceed ceiling and yet no non-zero count can become zero. This
  2126. X * scaling prevents errors in the weights of the interior nodes of the
  2127. X * Huffman tree and also ensures that the codes will fit in an unsigned
  2128. X * integer. Rescaling is used if necessary to limit the code length. 
  2129. X */
  2130. X
  2131. Xstatic int 
  2132. Xscale(ceil)
  2133. X    unsigned short    ceil;    /* upper limit on total weight */
  2134. X{
  2135. X    register int    i;
  2136. X    int             ovflw, divisor;
  2137. X    unsigned short    w, sum;
  2138. X    unsigned char   increased;    /* flag */
  2139. X
  2140. X    do {
  2141. X        for (i = sum = ovflw = 0; i < NUMVALS; ++i) {
  2142. X            if (node[i].weight > (ceil - sum))
  2143. X                ++ovflw;
  2144. X            sum += node[i].weight;
  2145. X        }
  2146. X
  2147. X        divisor = ovflw + 1;
  2148. X
  2149. X        /* Ensure no non-zero values are lost */
  2150. X
  2151. X        increased = FALSE;
  2152. X        for (i = 0; i < NUMVALS; ++i) {
  2153. X            w = node[i].weight;
  2154. X            if (w < divisor && w != 0) {    /* Don't fail to provide
  2155. X                             * a code if it's used
  2156. X                             * at all */
  2157. X
  2158. X                node[i].weight = divisor;
  2159. X                increased = TRUE;
  2160. X            }
  2161. X        }
  2162. X    } while (increased);
  2163. X
  2164. X    /* Scaling factor chosen, now scale */
  2165. X
  2166. X    if (divisor > 1)
  2167. X        for (i = 0; i < NUMVALS; ++i)
  2168. X            node[i].weight /= divisor;
  2169. X}
  2170. X
  2171. X/*
  2172. X * heap() and adjust() maintain a list of binary trees as a heap with the top
  2173. X * indexing the binary tree on the list which has the least weight or, in
  2174. X * case of equal weights, least depth in its longest path. The depth part is
  2175. X * not strictly necessary, but tends to avoid long codes which might provoke
  2176. X * rescaling. 
  2177. X */
  2178. X
  2179. Xstatic int 
  2180. Xheap(list, length)
  2181. X    int             list[], length;
  2182. X{
  2183. X    register int    i;
  2184. X    int             adjust();
  2185. X
  2186. X    for (i = (length - 2) / 2; i >= 0; --i)
  2187. X        adjust(list, i, length - 1);
  2188. X}
  2189. X
  2190. X/* Make a heap from a heap with a new top */
  2191. X
  2192. Xstatic int 
  2193. Xadjust(list, top, bottom)
  2194. X    int             list[], top, bottom;
  2195. X{
  2196. X    register int    k, temp;
  2197. X    int             cmptrees();
  2198. X
  2199. X    k = 2 * top + 1;    /* left child of top */
  2200. X    temp = list[top];    /* remember root node of top tree */
  2201. X
  2202. X    if (k <= bottom) {
  2203. X        if (k < bottom && cmptrees(list[k], list[k + 1]))
  2204. X            ++k;
  2205. X
  2206. X        /* k indexes "smaller" child (in heap of trees) of top */
  2207. X        /* now make top index "smaller" of old top and smallest child */
  2208. X
  2209. X        if (cmptrees(temp, list[k])) {
  2210. X            list[top] = list[k];
  2211. X            list[k] = temp;
  2212. X
  2213. X            /* Make the changed list a heap */
  2214. X
  2215. X            adjust(list, k, bottom);    /* recursive */
  2216. X        }
  2217. X    }
  2218. X}
  2219. X
  2220. X/*
  2221. X * Compare two trees, if a > b return true, else return false. Note
  2222. X * comparison rules in previous comments. 
  2223. X */
  2224. X
  2225. Xstatic int 
  2226. Xcmptrees(a, b)
  2227. X    int             a, b;    /* root nodes of trees */
  2228. X{
  2229. X    if (node[a].weight > node[b].weight)
  2230. X        return TRUE;
  2231. X    if (node[a].weight == node[b].weight)
  2232. X        if (node[a].tdepth > node[b].tdepth)
  2233. X            return TRUE;
  2234. X    return FALSE;
  2235. X}
  2236. X
  2237. X/*
  2238. X * HUFFMAN ALGORITHM: develops the single element trees into a single binary
  2239. X * tree by forming subtrees rooted in interior nodes having weights equal to
  2240. X * the sum of weights of all their descendents and having depth counts
  2241. X * indicating the depth of their longest paths. 
  2242. X *
  2243. X * When all trees have been formed into a single tree satisfying the heap
  2244. X * property (on weight, with depth as a tie breaker) then the binary code
  2245. X * assigned to a leaf (value to be encoded) is then the series of left (0)
  2246. X * and right (1) paths leading from the root to the leaf. Note that trees are
  2247. X * removed from the heaped list by moving the last element over the top
  2248. X * element and reheaping the shorter list. 
  2249. X */
  2250. X
  2251. Xstatic int 
  2252. Xbld_tree(list, len)
  2253. X    int             list[];
  2254. Xint             len;
  2255. X{
  2256. X    register int    freenode;    /* next free node in tree */
  2257. X    register struct nd *frnp;    /* free node pointer */
  2258. X    int             lch, rch;    /* temps for left, right children */
  2259. X    int             maxchar();
  2260. X
  2261. X    /*
  2262. X     * Initialize index to next available (non-leaf) node. Lower numbered
  2263. X     * nodes correspond to leaves (data values). 
  2264. X     */
  2265. X
  2266. X    freenode = NUMVALS;
  2267. X
  2268. X    while (len > 1) {    /* Take from list two btrees with least
  2269. X                 * weight and build an interior node pointing
  2270. X                 * to them. This forms a new tree. */
  2271. X
  2272. X        lch = list[0];    /* This one will be left child */
  2273. X
  2274. X        /* delete top (least) tree from the list of trees */
  2275. X
  2276. X        list[0] = list[--len];
  2277. X        adjust(list, 0, len - 1);
  2278. X
  2279. X        /* Take new top (least) tree. Reuse list slot later */
  2280. X
  2281. X        rch = list[0];    /* This one will be right child */
  2282. X
  2283. X        /*
  2284. X         * Form new tree from the two least trees using a free node
  2285. X         * as root. Put the new tree in the list. 
  2286. X         */
  2287. X
  2288. X        frnp = &node[freenode];    /* address of next free node */
  2289. X        list[0] = freenode++;    /* put at top for now */
  2290. X        frnp->lchild = lch;
  2291. X        frnp->rchild = rch;
  2292. X        frnp->weight = node[lch].weight + node[rch].weight;
  2293. X        frnp->tdepth = 1 + maxchar(node[lch].tdepth, node[rch].tdepth);
  2294. X
  2295. X        /* reheap list  to get least tree at top */
  2296. X
  2297. X        adjust(list, 0, len - 1);
  2298. X    }
  2299. X    dctreehd = list[0];    /* head of final tree */
  2300. X}
  2301. X
  2302. Xstatic int 
  2303. Xmaxchar(a, b)
  2304. X{
  2305. X    return a > b ? a : b;
  2306. X}
  2307. X
  2308. Xstatic int 
  2309. Xinit_enc()
  2310. X{
  2311. X    register int    i;
  2312. X
  2313. X    /* Initialize encoding table */
  2314. X
  2315. X    for (i = 0; i < NUMVALS; ++i)
  2316. X        codelen[i] = 0;
  2317. X}
  2318. X
  2319. X/*
  2320. X * Recursive routine to walk the indicated subtree and level and maintain the
  2321. X * current path code in bstree. When a leaf is found the entire code string
  2322. X * and length are put into the encoding table entry for the leaf's data value
  2323. X * . 
  2324. X *
  2325. X * Returns ERROR if codes are too long. 
  2326. X */
  2327. X
  2328. Xstatic int 
  2329. Xbuildenc(level, root)
  2330. X    int             level;    /* level of tree being examined, from zero */
  2331. X    int             root;    /* root of subtree is also data value if leaf */
  2332. X{
  2333. X    register int    l, r;
  2334. X
  2335. X    l = node[root].lchild;
  2336. X    r = node[root].rchild;
  2337. X
  2338. X    if (l == NOCHILD && r == NOCHILD) {    /* Leaf. Previous path
  2339. X                         * determines bit string code
  2340. X                         * of length level (bits 0 to
  2341. X                         * level - 1). Ensures unused
  2342. X                         * code bits are zero. */
  2343. X
  2344. X        codelen[root] = level;
  2345. X        code[root] = tcode & (((unsigned short    ) ~0) >> (16 - level));
  2346. X        return (level > 16) ? ERROR : 0;
  2347. X    } else {
  2348. X        if (l != NOCHILD) {    /* Clear path bit and continue deeper */
  2349. X
  2350. X            tcode &= ~(1 << level);
  2351. X            if (buildenc(level + 1, l) == ERROR)
  2352. X                return ERROR;    /* pass back bad statuses */
  2353. X        }
  2354. X        if (r != NOCHILD) {    /* Set path bit and continue deeper */
  2355. X
  2356. X            tcode |= 1 << level;
  2357. X            if (buildenc(level + 1, r) == ERROR)
  2358. X                return ERROR;    /* pass back bad statuses */
  2359. X        }
  2360. X    }
  2361. X    return NULL;        /* it worked if we reach here */
  2362. X}
  2363. X
  2364. Xstatic int 
  2365. Xput_int(n, f)            /* output an integer */
  2366. X    short        n;    /* integer to output */
  2367. X    FILE           *f;    /* file to put it to */
  2368. X{
  2369. X    putc_pak(n & 0xff, f);    /* first the low byte */
  2370. X    putc_pak(n >> 8, f);    /* then the high byte */
  2371. X}
  2372. X
  2373. X/* Write out the header of the compressed file */
  2374. X
  2375. Xstatic long 
  2376. Xwrt_head(ob)
  2377. X    FILE           *ob;
  2378. X{
  2379. X    register int    l, r;
  2380. X    int             i, k;
  2381. X    int             numnodes;    /* # of nodes in simplified tree */
  2382. X
  2383. X    /*
  2384. X     * Write out a simplified decoding tree. Only the interior nodes are
  2385. X     * written. When a child is a leaf index (representing a data value)
  2386. X     * it is recoded as -(index + 1) to distinguish it from interior
  2387. X     * indexes which are recoded as positive indexes in the new tree. 
  2388. X     *
  2389. X     * Note that this tree will be empty for an empty file. 
  2390. X     */
  2391. X
  2392. X    numnodes = dctreehd < NUMVALS ? 0 : dctreehd - (NUMVALS - 1);
  2393. X    put_int(numnodes, ob);
  2394. X
  2395. X    for (k = 0, i = dctreehd; k < numnodes; ++k, --i) {
  2396. X        l = node[i].lchild;
  2397. X        r = node[i].rchild;
  2398. X        l = l < NUMVALS ? -(l + 1) : dctreehd - l;
  2399. X        r = r < NUMVALS ? -(r + 1) : dctreehd - r;
  2400. X        put_int(l, ob);
  2401. X        put_int(r, ob);
  2402. X    }
  2403. X
  2404. X    return sizeof(short) + numnodes * 2 * sizeof(short);
  2405. X}
  2406. X
  2407. X/*
  2408. X * Get an encoded byte or EOF. Reads from specified stream AS NEEDED. 
  2409. X *
  2410. X * There are two unsynchronized bit-byte relationships here. The input stream
  2411. X * bytes are converted to bit strings of various lengths via the static
  2412. X * variables named c... These bit strings are concatenated without padding to
  2413. X * become the stream of encoded result bytes, which this function returns one
  2414. X * at a time. The EOF (end of file) is converted to SPEOF for convenience and
  2415. X * encoded like any other input value. True EOF is returned after that. 
  2416. X */
  2417. X
  2418. Xstatic int 
  2419. Xgethuff(ib)            /* Returns bytes except for EOF */
  2420. X    FILE           *ib;
  2421. X{
  2422. X    int             rbyte;    /* Result byte value */
  2423. X    int             need;    /* number of bits */
  2424. X
  2425. X    rbyte = 0;
  2426. X    need = 8;        /* build one byte per call */
  2427. X
  2428. X    /*
  2429. X     * Loop to build a byte of encoded data. Initialization forces read
  2430. X     * the first time. 
  2431. X     */
  2432. X
  2433. Xloop:
  2434. X    if (cbitsrem >= need) {    /* if current code is big enough */
  2435. X        if (need == 0)
  2436. X            return rbyte;
  2437. X
  2438. X        rbyte |= ccode << (8 - need);    /* take what we need */
  2439. X        ccode >>= need;    /* and leave the rest */
  2440. X        cbitsrem -= need;
  2441. X        return rbyte & 0xff;
  2442. X    }
  2443. X    /* We need more than current code */
  2444. X
  2445. X    if (cbitsrem > 0) {
  2446. X        rbyte |= ccode << (8 - need);    /* take what there is */
  2447. X        need -= cbitsrem;
  2448. X    }
  2449. X    /* No more bits in current code string */
  2450. X
  2451. X    if (curin == SPEOF) {    /* The end of file token has been encoded. If
  2452. X                 * result byte has data return it and do EOF
  2453. X                 * next time. */
  2454. X
  2455. X        cbitsrem = 0;
  2456. X        return (need == 8) ? EOF : rbyte + 0;
  2457. X    }
  2458. X    /* Get an input byte */
  2459. X
  2460. X    if ((curin = getc_ncr(ib)) == EOF)
  2461. X        curin = SPEOF;    /* convenient for encoding */
  2462. X
  2463. X    ccode = code[curin];    /* get the new byte's code */
  2464. X    cbitsrem = codelen[curin];
  2465. X
  2466. X    goto loop;
  2467. X}
  2468. X
  2469. X/*
  2470. X * This routine is used to perform the actual squeeze operation.  It can only
  2471. X * be called after the file has been scanned.  It returns the true length of
  2472. X * the squeezed entry. 
  2473. X */
  2474. X
  2475. Xlong 
  2476. Xfile_sq(f, t)            /* squeeze a file into an archive */
  2477. X    FILE           *f;    /* file to squeeze */
  2478. X    FILE           *t;    /* archive to receive file */
  2479. X{
  2480. X    int             c;    /* one byte of squeezed data */
  2481. X    long            size;    /* size after squeezing */
  2482. X
  2483. X    size = wrt_head(t);    /* write out the decode tree */
  2484. X
  2485. X    while ((c = gethuff(f)) != EOF) {
  2486. X        putc_pak(c, t);
  2487. X        size++;
  2488. X    }
  2489. X
  2490. X    return size;        /* report true size */
  2491. X}
  2492. ________This_Is_The_END________
  2493. if test `wc -c < arcsq.c` -ne    14613; then
  2494.     echo 'shar: arcsq.c was damaged during transit (should have been    14613 bytes)'
  2495. fi
  2496. fi        ; : end of overwriting check
  2497. exit 0
  2498.  
  2499. -- 
  2500. Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
  2501.  
  2502.  
  2503.